package syntelos.sx;

import alto.sys.Lock;

/**
 * <p> The SX Socket performs two independent roles beyond its super
 * class.  As the client socket it contains a reference to the {@link
 * Server} instance with the network socket.  As the server socket it
 * creates new client sockets in this pattern.  </p>
 * 
 * @author jdp
 * @since 1.6
 */
public class Socket
    extends syntelos.lang.Socket
{
    public final static class Local 
        extends java.lang.ThreadLocal<Socket>
    {

        public final static Local Instance = new Local();

        public final static Socket Get(){
            return Instance.get();
        }
        public final static Socket Enter(Socket ano){
            Instance.set(ano);
            return ano;
        }
        public final static void Exit(){
            Instance.set(null);
        }
    }

    public final static class Queue 
    {
        /**
         * An expression of load capacity in terms of thread capacity
         */
        private final static int Loading = 3;

        public final static int Depth(){
            return Pointer;
        }
        private final static Object Pool = new Object();
        private final static Lock Queue = new alto.sys.lock.Light();
        private final static int Term = (syntelos.sys.statistic.Proc.DepthByCount()*Loading);
        private final static Socket[] List = new Socket[Term];
        private static volatile int Pointer = 0;

        final static void Push(Socket socket){
            socket.enqueue();
            Queue.lockWriteEnter();
            try {
                int idx = Pointer;
                if (idx < Term){
                    Pointer = (idx+1);
                    List[idx] = socket;
                }
                else
                    throw new Overload(socket);
            }
            finally {
                Queue.lockWriteExit();
            }
            synchronized(Pool){
                Pool.notify();
                return;
            }
        }
        final static Socket Pop(){
            Queue.lockWriteEnter();
            try {
                if (0 < Pointer){
                    Pointer--;
                    Socket socket = List[0];
                    int len = Pointer;
                    if (0 < len)
                        System.arraycopy(List,1,List,0,len);
                    socket.dequeue();
                    return socket;
                }
                else
                    return null;
            }
            finally {
                Queue.lockWriteExit();
            }
        }
        final static Socket Waitfor()
            throws java.lang.InterruptedException
        {
            Socket socket = Pop();
            while (null == socket){
                synchronized(Pool){
                    Pool.wait();
                }
                socket = Pop();
            }
            return socket;
        }
    }
    

    private final Server server;



    public Socket(Server server, java.net.ServerSocket socket){
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }
    public Socket(Server server, java.net.Socket socket){
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }
    public Socket(Server server, java.net.DatagramSocket socket){
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }
    public Socket(Server server, java.net.MulticastSocket socket){
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }
    public Socket(Server server, syntelos.net.shm.Connection.Server socket)
        throws java.io.IOException
    {
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }
    public Socket(Server server, javax.net.ssl.SSLServerSocket socket)
        throws java.io.IOException
    {
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }
    public Socket(Server server, javax.net.ssl.SSLSocket socket)
        throws java.io.IOException
    {
        super(socket);
        if (null != server)
            this.server = server;
        else 
            throw new IllegalArgumentException();
    }


    public Server getServer(){
        return this.server;
    }


    @Override
    public alto.lang.Socket dequeue(){
        Socket.Local.Enter(this);
        /*
         * in Service thread
         */
        return super.dequeue();
    }
    @Override
    public alto.lang.Socket release(){
        Socket.Local.Exit();
        return super.release();
    }
    @Override
    public alto.lang.Socket acceptNewSocket(java.net.Socket client)
        throws java.io.IOException
    {
        if (client instanceof javax.net.ssl.SSLSocket)
            return new Socket(this.server,(javax.net.ssl.SSLSocket)client);
        else
            return new Socket(this.server,client);
    }
}
